 #include <sys/socket.h>
#include <string> 
       #include <netinet/in.h>
       #include <arpa/inet.h>
  #include <unistd.h>
#include <iostream>


enum class Status
{
    BEGING,
    CONNECTED,
    DISCONNECTED,
    FAILED
};




class TcpConnection
{
public:
    TcpConnection(std::string ip,int port)
    :_sockfd(-1)
    ,_ip(ip)
    ,_port(port)
    ,_interval(1)
    ,_times(5)
    ,_status(Status::BEGING)
    {}

    void Connect()
    {
        _sockfd= socket(AF_INET, SOCK_STREAM, 0);

        struct sockaddr_in dst;
        dst.sin_family=AF_INET;
        
        inet_aton(_ip.c_str(), &dst.sin_addr);
        dst.sin_port= htons(_port);

        int n= connect(_sockfd, (struct sockaddr*)&dst, sizeof(dst));
        if(n== 0)
        {
             _status= Status::CONNECTED;
        }
        else
        {
            close(_sockfd);
        }
    }

    void ReConnect()
    {
        int i=0;
        for(; i<_times; i++)
        {
            Connect();
            if(_status== Status::CONNECTED)
            {
                std::cout<<"第 "<<i+1<<" 次重连: 成功\n";
                break;
            }
            else if(_status== Status::DISCONNECTED)
            {
                std::cout<<"第 "<<i+1<<" 次重连: 失败\n";
            }

            sleep(_interval);
        }

        if(i== _times)
        {
            _status= Status::FAILED;
        }
    }


    Status GetStatus()
    {
        return _status;
    }

    void Process()
    {
        char buffer[1025];
        std::string s;
        while(1)
        {
            std::cout<<"please input# ";
            fflush(stdout);
            std::getline(std::cin, s);

            write(_sockfd, s.c_str(), s.size());

            int n= read(_sockfd, buffer, sizeof(buffer)-1);
            if(n> 0)
            {
                buffer[n]=0;
                std::cout<<buffer<<std::endl;
            }
            else if(n== 0)
            {
                close(_sockfd);
                _status= Status::DISCONNECTED;
                break;
            }
        }

    }



    
private:
    int _sockfd;
    std::string _ip;//目标ip
    int _port;//目的端口
    int _interval;//重连间隔
    int _times;//重连次数
    Status _status;
};



class TcpClient
{
public:
    TcpClient(int port, std::string ip)
    :_connection(ip, port)
    {}

    void Execute()
    {
        while(1)
        {
            switch(_connection.GetStatus())
            {
            case Status::BEGING:
                _connection.Connect();
                break;
            case Status::CONNECTED:
                _connection.Process();
                break;
            case Status::DISCONNECTED:
                _connection.ReConnect();
                break;
            }

            if(_connection.GetStatus()== Status::FAILED)
            {
                break;
            }
        }
    }
private:
    TcpConnection _connection;
};